package interceptors

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"io/ioutil"
	"mime"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"gpt-api/framework/ginplus"
	"gpt-api/framework/log"
)

// Logger 日志中间件
func Logger(skipper ...SkipperFunc) gin.HandlerFunc {
	return func(c *gin.Context) {
		if len(skipper) > 0 && skipper[0](c) {
			c.Next()
			return
		}

		var (
			payload []byte
			err     error
			//str     string
		)

		method := c.Request.Method
		start := time.Now()

		fields := make([]log.Field, 0, 11)
		fields = append(fields, log.String("x-request-id", ginplus.RequestID(c)))
		fields = append(fields, log.String("ip", ginplus.IP(c)))
		fields = append(fields, log.String("method", method))
		fields = append(fields, log.String("path", c.Request.URL.Path))
		fields = append(fields, log.String("url", c.Request.URL.String()))
		fields = append(fields, log.String("User-Agent", c.Request.UserAgent()))
		// 如果是POST/PUT请求，并且内容类型为JSON，则读取内容体
		if method == http.MethodPost || method == http.MethodPut {
			mediaType, _, _ := mime.ParseMediaType(c.GetHeader("Content-Type"))
			if mediaType == "application/json" {
				payload, err = ioutil.ReadAll(c.Request.Body)
				c.Request.Body.Close()
				if err == nil {
					buf := bytes.NewBuffer(payload)
					c.Request.Body = ioutil.NopCloser(buf)
					fields = append(fields, log.Int64("content_length", c.Request.ContentLength))
					fields = append(fields, log.String("body", string(payload)))
				} else {
					log.Error("read json request", log.String("x-request-id", ginplus.RequestID(c)), log.String("body", string(payload)), log.Errval(err))
				}
			}
		}

		// 验证请求签名 #{HTTP_METHOD}|#{PATH}|#{X-TIMESTAMP}|#{base64(PAYLOAD)}
		//str = fmt.Sprintf("%s|%s|%s", strings.ToLower(c.Request.Method), c.Request.URL.String(), ginplus.ApiTimestamp(c))
		//if len(payload) > 0 {
		//	str += "|" + base64.StdEncoding.EncodeToString(payload)
		//}
		//apiKey := ginplus.ApiKey(c)
		//if getSignature(str, viper.GetString(apiKey)) != ginplus.ApiSignature(c) {
		//	// todo
		//	//ginplus.ReplyForbidden(c, nil) // 非法访问
		//	//c.Abort()
		//	//return
		//}

		c.Next()

		fields = append(fields, log.Int64("cost_time", time.Since(start).Nanoseconds()/1e6))
		fields = append(fields, log.Int("res_status", c.Writer.Status()))
		fields = append(fields, log.Int("res_length", c.Writer.Size()))

		log.Info("[http]", fields...)
	}
}

func getSignature(str string, secret string) string {
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(str))
	return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}

type bodyLogWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

func (w bodyLogWriter) Write(b []byte) (int, error) {
	w.body.Write(b)
	return w.ResponseWriter.Write(b)
}
